﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using RobotEscape.Screens;
using System.Linq;

namespace RobotEscape.Entities
{
    public class Player : SpriteEntity
    {
        protected double lastMoveTime = 0;
        Level level;
        double newPosX = 0, newPosY = 0;
        double targetX = -1, targetY = -1;
        Sprite spriteStanding;
        Sprite spriteDying;
        bool moving = false;
        bool dying = false;
        double dyingStartTime = 0;
        double winStartTime = 0;
        public double walkspeed = 0.2;
        public bool Activated = false;
        public bool Slave = false;
        public bool Corrupted = false;
        private bool _exitOpen = false;
        public int PlayerNum = 1;
        public bool ExitOpen
        {
            get
            {
                if (!_exitOpen)
                {
                    Exit exit = this.level.GameScreen.entities.OfType<Exit>().ToList()[0];
                    if (exit.allOpen)
                    {
                        _exitOpen = true;
                    }
                }
                return _exitOpen;
            }
        }

        public Player(Level _level, bool slave = false)
        {
            this.level = _level;
            this.Slave = slave;

            this.width = 20;
            this.height = 20;
            // sprite information
            spriteStanding = new Sprite();
            spriteStanding.file = "Assets/images/entities.png";
            spriteStanding.frameCount = 1;
            spriteStanding.x = 0;
            spriteStanding.y = 0;
            spriteStanding.width = 20;
            spriteStanding.height = 20;

            // sprite information
            spriteDying = new Sprite();
            spriteDying.file = "Assets/images/entities.png";
            spriteDying.frameCount = 3;
            spriteDying.fps = 3;
            spriteDying.x = 0;
            spriteDying.y = 20;
            spriteDying.width = 20;
            spriteDying.height = 20;
            spriteDying.loop = false;

            if (slave)
            {
                spriteStanding.y += 40;
                spriteDying.y += 40;
            }
        }

        public override void Update(GameTime time)
        {
            if (targetX < 0)
            {
                targetX = PosX;
                targetY = PosY;
            }
            newPosX = PosX;
            newPosY = PosY;

            if (moving)
                Move(time);
            else
                ProcessKeys(time);
            

            if (!dying)
            {
                foreach (Hazzard h in level.GameScreen.entities.OfType<Hazzard>())
                {
                    if (h.CollidesWith(this))
                    {
                        Die(time);
                    }
                }

                foreach (Corruptor corruptor in level.GameScreen.entities.OfType<Corruptor>())
                {
                    if (corruptor.CollidesWith(this))
                    {
                        if (!this.Corrupted)
                        {
                            Sound.Play(Sounds.Corruptor);
                        }
                        this.Corrupted = true;
                    }
                }

                foreach (Exit exit in this.level.GameScreen.entities.OfType<Exit>())
                {
                    if (exit.CollidesWith(this))
                    {
                        if (exit.allOpen)
                        {
                            if (winStartTime == 0)
                                winStartTime = time.TotalRealTime.TotalMilliseconds;
                            else if (time.TotalRealTime.TotalMilliseconds - winStartTime > 1000)
                            {
                                if (level.LevelNumber >= Game.Instance.LEVEL_COUNT)
                                    Game.Instance.SwitchScreen(new FinalWinScreen(level.GameScreen), false);
                                else
                                    Game.Instance.SwitchScreen(new WinScreen(level.GameScreen), false);
                            }
                        }
                        else
                        {
                            Die(time);
                        }
                    }
                }
            }

            if (dying)
                base.Update(time, spriteDying);
            else
                base.Update(time, spriteStanding);

            if (dying && this.doneAnimating && (!this.Slave || !this.ExitOpen))
            {
                Game.Instance.SwitchScreen(new LoseScreen(this.level.GameScreen), false);
            }
        }

        private void Move(GameTime time)
        {
            bool arrivedX = (newPosX == targetX);
            bool arrivedY = (newPosY == targetY);
            if (!arrivedX && newPosX < targetX)
            {
                newPosX += walkspeed * time.ElapsedRealTime.TotalMilliseconds;
                if (newPosX >= targetX)
                    arrivedX = true;
            }
            else if (!arrivedX && newPosX > targetX)
            {
                newPosX -= walkspeed * time.ElapsedRealTime.TotalMilliseconds;
                if (newPosX <= targetX)
                    arrivedX = true;
            }

            if (!arrivedY && newPosY < targetY)
            {
                newPosY += walkspeed * time.ElapsedRealTime.TotalMilliseconds;
                if (newPosY >= targetY)
                    arrivedY = true;
            }
            else if (!arrivedY && newPosY > targetY)
            {
                newPosY -= walkspeed * time.ElapsedRealTime.TotalMilliseconds;
                if (newPosY <= targetY)
                    arrivedY = true;
            }

            if (arrivedX && arrivedY)
            {
                moving = false;
                newPosX = targetX;
                newPosY = targetY;
            }
            PosX = newPosX;
            PosY = newPosY;
        }

        private void ProcessKeys(GameTime time)
        {
            if (dying) return;
            if (!Activated) return;
            // get current tile
            Point p = level.GetClosestTile(PosX, PosY);
            int xinc = 0, yinc = 0;
            // add or subtract 1
            if (KeyState.GetKeyState(Key.Left) || KeyState.GetKeyState(Key.A))
            {
                moving = true;
                xinc = -1;
            }
            if (KeyState.GetKeyState(Key.Right) || KeyState.GetKeyState(Key.D))
            {
                moving = true;
                xinc = 1;
            }
            if (KeyState.GetKeyState(Key.Up) || KeyState.GetKeyState(Key.W))
            {
                moving = true;
                yinc = -1;
            }
            if (KeyState.GetKeyState(Key.Down) || KeyState.GetKeyState(Key.S))
            {
                moving = true;
                yinc = 1;
            }

            if (Corrupted)
            {
                xinc *= -1;
                yinc *= -1;
            }

            p.X += xinc;
            p.Y += yinc;

            // if the x tile is free
            if (level.GetCollision((int)p.X, (int)PosY / Tile.Size) == TileCollision.Passable)
            {
                // translate back to pixels
                targetX = p.X * Tile.Size;
            }
            if (level.GetCollision((int)PosX / Tile.Size, (int)p.Y) == TileCollision.Passable)
            {
                targetY = p.Y * Tile.Size;
            }

            // to handle the diagonal
            if (level.GetCollision((int)targetX / Tile.Size, (int)targetY / Tile.Size) != TileCollision.Passable)
            {
                targetX = PosX;
                targetY = PosY;
            }


            foreach (Spike spike in this.level.GameScreen.entities.OfType<Spike>())
            {
                if (spike.CollidesWith((int)p.X * Tile.Size, (int)p.Y * Tile.Size))
                {
                    Die(time);
                }
            }
        }

        public void Die(GameTime time)
        {
            Sound.Play(Sounds.Die);
            dyingStartTime = time.TotalRealTime.TotalMilliseconds;
            dying = true;
        }
    }
}
